package www.cskaoyan.com.utils;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class Server {

    public void start(){
        // 创建线程池
        // ExecutorService pool = Executors.newFixedThreadPool(10);
        try {
            ServerSocket serverSocket = new ServerSocket(8084);
            while (true){
                Socket socket = serverSocket.accept();
                // 将线程池中提交Runnable类型的任务,可修改为多线程
                // pool.submit(new ConnectTask(socket));
                InputStream inputStream = socket.getInputStream();
                // 处理请求
                Request request = dealRequest(inputStream);

                Response response = null;
                if (request.getMethods().toUpperCase().equals("OPTIONS")){
                    // OPTIONS请求不做处理
                }else {
                    // 调用分发器分发请求, 获得结果
                    Dispatcher dispatcher = new Dispatcher();
                    response = dispatcher.dispatch(request);
                }

                // 处理响应
                OutputStream outputStream = socket.getOutputStream();
                response(outputStream, response);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }



    public Request dealRequest(InputStream inputStream) throws IOException {
        Request request = new Request();

        // 获取请求报文
        String content = getRequestContent(inputStream);

        // 获取请求的URL
        String requestURL = getRequestURL(content);
        request.setUrl(requestURL);

        // 获得请求方式
        String requestMethod = getRequestMethods(content);
        request.setMethods(requestMethod);

        // 获取请求的参数
        HashMap parameters = request.getParameters();
        if (requestMethod.equals("GET") ){// GET请求
            getRequestParametersByGet(content, parameters);
        }else {// POST请求
            getRequestParametersByPost(content, parameters);
        }
        return  request;
    }


    /**
     * 请求请求报文获取POST请求的参数
     * @param content: 请求报文
     * @param parameters: 存储报文的容器
     */
    private void getRequestParametersByPost(String content, HashMap parameters) {
        // 判断报文信息是否存在
        if(content != null && !"".equals(content)){

            int beginBracket = content.indexOf("{");
            int endBracket = content.indexOf("}");

            // 判断是否在正文存在参数
            if (beginBracket != -1 && endBracket != -1 && endBracket-beginBracket>7) {
                String parametersString = content.substring(beginBracket + 1, endBracket);

                if (parametersString.indexOf(",") != -1){
                    // 多个参数
                    String[] parmList = parametersString.split(",");
                    for (String parm : parmList) {
                        String[] split = parm.split(":");
                        parameters.put(split[0].substring(1, split[0].length()-1),
                                split[1].substring(1, split[1].length()-1) );
                    }
                }else {
                    // 一个参数
                    String[] split = parametersString.split(":");
                    parameters.put(split[0].substring(1, split[0].length()-1),
                            split[1].substring(1, split[1].length()-1) );
                }
            }
        }
    }

    /**
     * 请求请求报文获取GET请求的参数
     * @param content: 请求报文
     * @param parameters: 存储报文的容器
     */
    private void getRequestParametersByGet(String content, HashMap parameters) {
        // 判断报文信息是否存在
        if(content != null && !"".equals(content)){
            // 获得虚拟路径+参数的起始下标
            int a = content.indexOf(' ');
            // 获得虚拟路径+参数的结束下标
            int b = content.indexOf(' ',a + 1);
            // 截取虚拟路径+参数
            String fileName = content.substring(a + 2, b);
            // 获得参数标记的起始位置
            int i = fileName.indexOf('?');

            if(i != -1){
                // 有参数: 对参数进行处理
                String parametersString = fileName.substring(i+1, fileName.length());

                if (parametersString.indexOf('&') == -1){
                    // 仅仅一个参数: eg : zs=18, 把这个数据存储进参数容器

                    int connectionSymbol = parametersString.indexOf("=");
                    String key = parametersString.substring(0, connectionSymbol);
                    String value = parametersString.substring(connectionSymbol+1, parametersString.length());
                    parameters.put(key, value);

                }else {
                    // 多个参数: 获得每个参数的键值对数组
                    String[] split = parametersString.split("&");

                    // 对每一个参数都处理, 存储进参数容器
                    for (String s : split) {
                        int connectionSymbol = s.indexOf("=");
                        String key = s.substring(0, connectionSymbol);
                        String value = s.substring(connectionSymbol+1, s.length());
                        parameters.put(key, value);
                    }
                }
            }else {
                // 无参数
                return ;
            }
        }
    }

    /**
     * 根据接收的请求货物请求报文信息
     * @param inputStream: 请求输入流
     * @return 报文字符串信息
     * @throws IOException
     */
    private String getRequestContent(InputStream inputStream) throws IOException {

        StringBuffer stringBuffer = new StringBuffer();
        InputStreamReader in = new InputStreamReader(inputStream);

        BufferedReader br = new BufferedReader(in);
        char[] chars = new char[4096000];
        int readCount = br.read(chars);
        String s = new String(chars, 0, readCount);
        stringBuffer.append(s);

        return stringBuffer.toString();
    }

    /**
     * 根据请求报文获取请求的请求方式
     * @param content: 请求报文信息
     * @return: 请求的请求方式
     */
    private String getRequestMethods(String content) {
        // 判断报文信息是否存在
        if(content != null && !"".equals(content)){
            // 获得第一个空格
            int a = content.indexOf(' ');

            // 切割出请求方式
            String requestMethod = content.substring(0, a);
            String requestMethods = requestMethod.toUpperCase();

            return requestMethods;
        }
        return null;
    }

    /**
     * 根据请求报文获取请求的URL
     * @param content: 请求报文信息
     * @return: 请求的url
     */
    public String getRequestURL(String  content){
        // 判断报文信息是否存在
        if(content != null && !"".equals(content)){
            // 获得虚拟路径+参数的起始下标
            int a = content.indexOf(' ');
            // 获得虚拟路径+参数的结束下标
            int b = content.indexOf(' ',a + 1);
            // 截取虚拟路径+参数
            String fileName = content.substring(a + 2, b);
            // 获得参数标记的起始位置
            int i = fileName.indexOf('?');

            if(i != -1){
                // 有参数: 切割出虚拟路径
                return fileName.substring(0,i);
            }else {
                // 无参数: 直接返回虚拟路径
                return fileName;
            }
        }
        return null;
    }


    public void response(OutputStream outputStream, Response response) throws IOException {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("HTTP/1.1 200 ok \r\n");
        stringBuffer.append("Access-Control-Allow-Headers: " +
                "DNT,X-Mx-ReqToken,Keep-Alive,User-Agent," +
                "X-Requested-With,If-Modified-Since,Cache-Control," +
                "Content-Type,Authorization \r\n" );
        stringBuffer.append("Content-Type: application/json;charset=UTF-8 \r\n");
        stringBuffer.append("Access-Control-Allow-Methods: POST, GET, OPTIONS \r\n");
        stringBuffer.append("Access-Control-Allow-Origin: * \r\n");
        stringBuffer.append("\r\n");

        // response是 null 代表 OPTIONS请求
        if (response != null){
            String resData = getJsonData(response);
            stringBuffer.append(resData);
        }

        outputStream.write(stringBuffer.toString().getBytes("utf-8"));
        outputStream.close();

    }

    private String getJsonData(Response response) {
        StringBuffer buffer = new StringBuffer();
        buffer.append("{");
        // 状态
        buffer.append("\"status\":").append(response.getStatus()).append(",");
        // errorMsg
        if (response.getErrorMsg() != null)
        buffer.append("\"errorMsg\":\"").append(response.getErrorMsg()).append("\",");
        // sucessMsg
        if (response.getSucessMsg() != null)
        buffer.append("\"sucessMsg\":\"").append(response.getSucessMsg()).append("\",");

        if (response.getData() != null){
            buffer.append("\"data\":");
            SplicJson.appJson(response.getData(), buffer);
            buffer.append("}");
            System.out.println(buffer.toString());
            return buffer.toString();
        }else {
            // 消除一个,
            String substring = buffer.substring(0, buffer.length() - 1) + "}";
            return substring;
        }
    }




}
